<?php
/** tp5.1数据库操作学习 */

namespace app\index\controller;

use think\Controller;
use think\Db;
use think\Exception;
use think\Facade\Request;

//use think\Db;
class XueDb extends Controller
{

    public function find()
    {
        /** 查询单条数据 使用find 方法
         *  如果没找到结果,返回null, 否则返回结果数组
         */
        $row = Db::table('zh_user')->where('is_admin', '=', 1)->find();
        dump($row);
    }

    /** 如果希望在没有找到数据后抛出异常可以使用 findOrFail */
    public function findOrFail($id = 1, $name = '')
    {
        strlen(Request::param('id')) ? $id = Request::param('id') : null;
        $row = Db::name('user')->where('id', $id)->findOrFail();
        dump($row);
    }

    /** V5.1.23+版本开始，支持findOrEmpty方法，当查询不存在的时候返回空数组而不是Null。 */
    public function findOrEmpty($name = '')
    {
        strlen(Request::param('name')) ? $name = Request::param('name') : null;
        $row = Db::name('user')->where('name', 'like', "%$name%")->findOrEmpty();
        dump($row);
    }

    /**
     * 查询多条数据(数据集)使用 select 方法
     * 默认情况下，find和select方法返回的都是数组，区别在于后者是二维数组。
     */

    public function select()
    {
        $rows = Db::name('user')->select();
        dump($rows);
//        dump(count($rows));

    }

    /**
     * 助手函数
     * tp51提供了一个 db 助手函数,可以更方便查询
     * db()函数的第一个参数的作用和 name 方法一样(传入不带前缀的表名), 如果需要使用不同的数据库连接,
     * 可以传入数据库配置作为第二个参数  如:db('user','db_config1')->where('id',1')->find();
     */
    public function dbFun()
    {
        $row = db('user')->where('id', 1)->find();   //返回一条数据
        dump($row);
    }

    public function dbFun1()
    {
        $rows = db('user', 'db_local')->where('is_admin', 1)->select();
        dump($rows);
    }

    /** 值与列查询  */

    public function value($id = 1)
    {
        /** 查询某个字段的值 */
        /** 使用value()方法 根据 ID 查询 姓名,如果未匹配到数据 返回 null **/
        Request::param('id') ? $id = Request::param('id') : null;
        $v = Db::name('user')->where('id', $id)->value('name');
        dump($v);
    }

    public function column($is_admin = '')
    {
        /** 查询某一列的值 */

        strlen(Request::param('is_admin')) ? $is_admin = Request::param('is_admin') : null;
        $column = Db::connect('db_local')->name('user')->where('is_admin', $is_admin)->column('name');
        dump($column); //返回一个数组

    }

    public function column1($is_admin = '')
    {
        strlen(Request::param('is_admin')) ? $is_admin = Request::param('is_admin') : null;
        $column = Db::name('user')->where('is_admin', $is_admin)->column('name', 'id');
        dump($column); //返回由 id 为key的数组  ,也可以指定其它字段为key

    }

    public function column2($is_admin = '')
    {
        strlen(Request::param('is_admin')) ? $$is_admin = Request::param('is_admin') : null;
        $column = Db::connect('db_local')->name('user')->where('is_admin', $is_admin)->column('*', 'id');
        dump($column); //返回由 id 为key的二维数组
    }

    /**
     * 数据分批处理
     * 如果要处理成百上千条数据库记录,可以使用 chunk 方法,一次获取结果集的一小块,
     * 填充到要处理的闭包,些方法在编写处理大量数据库记录的时候非常有用.
     * 可以通过从闭包函数中返回 false 来中止后续数据的处理.
     */

    public function chunk()
    {
        Db::name('user')
            ->where('is_admin', 0)
            ->field('id,name,is_admin')
            ->chunk(100, function ($users) {
                foreach ($users as $user) {
                    dump($user);
                    if ($user['id'] == 1200) {
                        return false;
                    }

                    //code here
                }
            }, 'id', 'desc');
    }

    /**
     * 大批量数据处理
     * 如果需要处理大量的数量,可以使用新版提供的游标查询功能,该查询 方式利用了php的生成器特性,可以大幅减少大量数据查询 的内存占用问题
     *
     */
    public function cursor()
    {
        $cursor = Db::name('user')->where('is_admin', 0)->cursor();
        foreach ($cursor as $user) {
            echo $user['name'] . '<br>';
        }
    }


    /**
     * JSON类型数据查询（ mysql ）
     */

    public function json()
    {
        $row = Db::name('device')
            ->where('info->deviceid', '000008')
            ->find();
        echo($row['info']);
    }

    public function json1()
    {
        $rs = Db::table('zh_device')
            ->json(['info'])
            ->where('info->customer', '小泥吧科技')
            ->find();

        dump($rs);
    }

    public function jsonUpdate()
    {

//        $data['info->customer']='xiaoniba';
        $rs = Db::table('zh_device')
            ->where('deviceid', '000008')
            ->json(['info'])
            ->update([
//                'info->customer' => '小泥吧科技',
//                'info->desc' => '小泥吧公司财务机',
                'info->motherboard' => '技嘉主板',
            ]);

        dump($rs);
    }


    /**
     * where()方法支持,原生sql查询  对于一些实在复杂的查询，也可以直接使用原生SQL语句进行查询，例如：
     */
    public function sql($id = 1, $xin = '')
    {
        $id = Request::param('id');
        $xin = Request::param('xin');
        $rs = Db::name('user')
            ->where("id > $id AND name LIKE '$xin%'")
            ->select();

        for ($i = 0; $i < count($rs); $i++) {
            echo $rs[$i]['id'] . '--' . $rs[$i]['name'] . '<br>';
        }

    }

    /** 为了安全起见，我们可以对字符串查询条件使用参数绑定，例如: */

    public function safeSql($id = 1, $xin = '')
    {
        $id = Request::param('id');
        $xin = Request::param('xin');
        $rs = Db::name('user')
            ->whereRaw("id > :id AND name LIKE :name", ["id" => $id, "name" => $xin . '%'])
            ->select();
        for ($i = 0; $i < count($rs); $i++) {
            echo $rs[$i]['id'] . '--' . $rs[$i]['name'] . '<br>';

        }

    }

    /**
     * 还有两个原生查询方法  query()和execute()
     * query方法用于执行SQL查询操作，如果数据非法或者查询错误则返回false，否则返回查询结果数据集（同select方法）。
     * execute用于更新和写入数据的sql操作，如果数据非法或者查询错误则返回false，否则返回影响的记录数。
     *支持在原生查询的时候使用参数绑定，包括问号占位符或者命名占位符
     */
    public function query()
    {
        $id = Request::param('id');
        $name = Request::param('name');
        $rs = Db::query(
            "SELECT * FROM zh_user WHERE  id > :id  AND name LIKE :name",
            ['id' => $id, 'name' => "$name%"]
        );

        for ($i = 0; $i < count($rs); $i++) {
            echo $rs[$i]['id'] . '--' . $rs[$i]['name'] . '<br>';

        }
    }

    public function execute()
    {
        $id = Request::param('id');
        $name = Request::param('name');
        $mobile = Request::param('mobile');

        $r = Db::execute(
            "update zh_user set name=:name ,mobile=:mobile where id=:id",
            ['name' => $name, 'mobile' => $mobile, 'id' => $id]
        );
    }

    function callback($query)
    {
        echo "操作成功";
        dump($query);
    }


    /**
     *  ************************************************添加数据********************************
     */

    public function insert()
    {
        $data = [
            'name' => '石博華',
            'email' => 'shibohua@qq.com',
            'mobile' => '17312345678',
            'create_time' => time(),
            'update_time' => time(),
        ];
        $rs = Db::name('user')->insert($data);
        dump($rs);
    }

    /** 如果数据包含不存在的字段 insert()会抛出异常,如果想忽略不存在的字段,可以调用strict(false) */
    public function insert1()
    {
        $data = [
            'name' => '石博華111',
            'email' => 'shibohua@qq.com',
            'mobile' => '17312345678',
            'create_time' => time(),
            'update_time' => time(),
            'aa_time' => time(), //数据库不存在此字段
        ];
        $rs = Db::name('user')->strict(false)->insert($data);
        dump($rs);
    }

    public function insert2()
    {
        /** 如果是mysql数据库,支持replace写入 */
        $data = [
            'name' => '张三',
            'email' => 'zhangsan@xiaoniba.com',
            'mobile' => '13845544548',
            'create_time' => time(),

        ];

        $rs = Db::name('user')->insert($data, true);
        echo "插入{$rs}条数据 " . date('m-d H:i:s', time());
    }

    /** 添加数据后如果需要返回新增数据的自增主键,使用 insertGetId 方法 */
    public function insertGetId()
    {
        $data = [
            'name' => '张三',
            'email' => 'zhangsan@xiaoniba.com',
            'mobile' => '13845544548',
            'create_time' => time(),

        ];
        $id = Db::name('user')->insertGetId($data);
        echo "本条数据id为{$id},插入时间:" . date('m-d H:i:s');
    }

    /** 添加多条数据直接向 Db 类的 insertAll 方法传入需要添加的数据即可 */
    public function insertAll()
    {
        $data = [
            ['name' => '小可爱' . rand(1000, 9000), 'email' => 'xiaokeai' . rand(1000, 9000) . '@xnb.me', 'mobile' => '138' . rand(10000000, 99999999), 'create_time' => time(),],
            ['name' => '小可爱' . rand(1000, 9000), 'email' => 'xiaokeai' . rand(1000, 9000) . '@xnb.me', 'mobile' => '138' . rand(10000000, 99999999), 'create_time' => time(),],
            ['name' => '小可爱' . rand(1000, 9000), 'email' => 'xiaokeai' . rand(1000, 9000) . '@xnb.me', 'mobile' => '138' . rand(10000000, 99999999), 'create_time' => time(),],
            ['name' => '小可爱' . rand(1000, 9000), 'email' => 'xiaokeai' . rand(1000, 9000) . '@xnb.me', 'mobile' => '138' . rand(10000000, 99999999), 'create_time' => time(),],
            ['name' => '小可爱' . rand(1000, 9000), 'email' => 'xiaokeai' . rand(1000, 9000) . '@xnb.me', 'mobile' => '138' . rand(10000000, 99999999), 'create_time' => time(),],
        ];
//        $rs = Db::name('user')->insertAll($data);
//        $rs = Db::name('user')->insertAll($data,true); /** 如果是mysql 支持replace 写入 */
        /** 也可以使用 data() 方法 */
//        $rs = Db::name('user')->data($data)->insertAll();
        /** 如果数据比较多,可以分批插入,使用 limit() 指定每次插入的数量限制  */
        $rs = Db::name('user')->data($data)->limit(2)->insertAll();
        dump($rs);
        /** insertAll()返回添加数据的条数 */
    }


    /** 更新数据 */
    public function update()
    {

        $rows = Db::name('user')->where('id', 2728)->update(['name' => 'xiaoxiao1', 'update_time' => time()]);
        dump($rows);
        /** update()方法返回影响数据的条数,没修改任何数据 返回 0 */
    }

    /** 也可使用 data() 方法传入数据  */

    public function update1()
    {
        $data = [
            'name' => '小蜜',
            'update_time' => time(),
        ];
        $rs = Db::name('user')->data($data)->where('id', '>', 2700)->update();
        dump($rs);
    }

    /** 如果 数据中包含主键,可不用where() */
    public function update2()
    {
        $rs = Db::name('user')->update(['id' => 2681, 'mobile' => 88888888]);
        dump($rs);
    }

    /** 如果要更新的数据需要使用 sql 函数或者其它字段,可以使用下面的方式 */
    public function update3()
    {
        $rs = Db::name('user')
            ->where('id', 2681)
            ->inc('level', 2)
            ->dec('update_time', 1000)
            ->exp('name', 'UPPER(name)')
            ->update();
        dump($rs);

    }

    /** V5.1.7+ 以后的版本,支持使用 raw 方法进行数据更新,适合在数组更新的情况 */

    public function update4()
    {

        Db::name('user')
            ->where('id', 2681)
            ->update([
                'name' => Db::raw('UPPER(name)'),
                'level' => Db::raw('level+3'),
                'update_time' => Db::raw('update_time+3600'),
            ]);
    }

    /** 更新字段值 */
    public function update5()
    {
        $rs = Db::name('user')
            ->where('level', 2)
            ->setField('level', '0');
        dump($rs);
    }

    /** setInc/setDec 方法自增或自减一个字段的值(如不加第二个参数,默认步长为1) ,传入第三个参数支延时更新 */
    public function update6()
    {
        $rs = Db::name('user')
            ->where('id', 2681)
            ->setInc('level', 2, 2);
        dump($rs);
    }



    /** *******************************删除数据 **************************************/

    /** delete()返回删除的条数,,没有匹配数据返回 0
     * 不带条件调用 delete()方法会提示错误,如果 确实需要删除所有数据 ,可台使用 delete(true);
     */

    public function del($id = '')
    {
        $id = intval(Request::param('id'));
        $rs = Db::name('user')->delete($id);
        if ($rs > 0) {
            echo "删除了{$rs}条数据 ." . date('Y-m-d H:i:s', time());
        } else {
            echo '未删除数据' . date('Y-m-d H:i:s', time());
        }

    }

    public function del1()
    {
        $id = Db::name('user')->order('id', 'desc')->find()['id'];
        $rs = Db::name('user')->where('id', $id)->delete();
        dump($rs);
    }


    public function del2()
    {
        Db::table('think_user')->where('id', 1)->delete();
        Db::table('think_user')->where('id', '<', 10)->delete();
    }

    public function softDel()
    {
        $id = Db::name('user')->order('id', 'desc')->find()['id'];
        $rs = Db::name('user')->where('id', $id)->useSoftDelete('delete_time', time())->delete();
        dump($rs);
    }


    /** 查询事件
     *数据库的CURD操作支持事件,包括:
     * before_select   before_find    after_insert    after_update   after_delete
     * 查询事件仅支持 find  select  insert   update  和  delete 方法
     * 用 Db::event('事件','回调函数')注册事件
     * 查询事件的方法参数只有一个：当前的查询对象。但你可以通过依赖注入的方式添加额外的参数。
     */

//    public function evnTest(){
//        Db::event('after_insert', 'callback');
//        Db::event('before_select', function ($query) {
//            // 事件处理
//            return $result;
//        });
//    }

    /** 获取器
     *Db类也可以支持获取器定义，
     * withAttr方法可以多次调用，对多个字段定义获取器。
     */

    public function dbHuoQuQi()
    {
        $rs = Db::name('user')
            ->withAttr('email', function ($value, $data) {
                return strtoupper($value);
            })
            ->limit(20)
            ->select();

        foreach ($rs as $v) {
            echo '<pre>';
            echo $v['id'] . '--' . $v['name'] . ' : ' . $v['email'] . '<br>';
            echo '</pre>';
        }
    }


}